package com.ubb.dbms.core.fileManagers.dataFileManager;

import static com.ubb.dbms.core.fileManagers.binaryFileManager.BinaryFileUtils.offsetToRowNr;
import static com.ubb.dbms.core.fileManagers.binaryFileManager.BinaryFileUtils.rowNrToOffset;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Map;

import com.ubb.dbms.core.fileManagers.binaryFileManager.BinaryFileIO;
import com.ubb.dbms.domain.queryData.TableRowElements;
import com.ubb.dbms.domain.queryResult.RawDataConverter;
import com.ubb.dbms.domain.queryResult.SelectedRow;
import com.ubb.dbms.domain.xml.Table;
import com.ubb.dbms.domain.xml.TableAttribute;

public class DataFileIO extends BinaryFileIO {
	
	public DataFileIO() {
		super();
	}
	
	public DataFileIO(String fileName, String rsFileName, int headerLength,
			int rowLength) {
		super(fileName, rsFileName, headerLength, rowLength, false);
	}

	public void createDirectoryIfNotExists(String databasesFolderName) {
		super.handleCreateDirectoryIfNotExists(databasesFolderName);
	}

	public int insertRow(TableRowElements rowElements, Table table) {
		byte[] row = convertToByteArray(rowElements, table);
		int offsetInFile = super.handleInsertRow(row);
		int rowNr = offsetToRowNr(offsetInFile, headerLength, rowLength);
		return rowNr;
	}

	private byte[] convertToByteArray(TableRowElements rowElements, Table table) {
		try {
		ByteArrayOutputStream rowStream = new ByteArrayOutputStream(Integer.parseInt(table.getRowLenght()));
			for (TableAttribute attribute : table.getStructure().getAttributeList()) {
				Object value = rowElements.getColumnValue(attribute.getAttributeName());
				if (value != null) {
					String columnType = attribute.getType();
					int columnLength = Integer.parseInt(attribute.getLength());
					byte[] valueInByteArray;
					if ("int".equalsIgnoreCase(columnType)) {								// int
						valueInByteArray = ByteBuffer.allocate(columnLength).putInt(Integer.parseInt(value.toString())).array();
						rowStream.write(valueInByteArray);
					} else {																// varchar
						valueInByteArray = String.valueOf(value).getBytes();
						rowStream.write(valueInByteArray);
						// need to write after writing the valueOfArray
						rowStream.write(new byte[columnLength - valueInByteArray.length]);
					}
				}
				else {
					rowStream.write(new byte[Integer.parseInt(attribute.getLength())]);
				}
			}
			return rowStream.toByteArray();
		} catch (NumberFormatException e) {
			System.out.println("NumberFormatException in DataFileIO.convertToByteArray. Can be tableLength or attribute's length. " + e);
		} catch (IOException e) {
			System.out.println("Error while converting rowElements to byte[]. " + e);
		}
		return new byte[0];
	}

	public SelectedRow readRow(Table table, int offset) {
		return this.readRow(table, offset, RawDataConverter.FULL_PROJECTION_MAP);
	}

	public SelectedRow readRow(Table table, int rowNr, Map<String, String> projections) {
		int offset = rowNrToOffset(rowNr, headerLength, rowLength);
		byte[] row = super.handleReadRow(offset);
		SelectedRow selectedRow = RawDataConverter.convertRawData(table, row, projections);
		return selectedRow;
	}

	public int getNextNotDeletedRowNr(int rowNr) {
		byte[] rsRow;
		while ((rsRow = super.handleReadRowFromRsFile(rowNr)) != null && rsRow[0] != 0) {
			rowNr++;
		}
		return ++rowNr;	// get the next
	}

}
